package com.advertisementsystem.task;

import com.advertisementsystem.Mapper.AdScheduleMapper;
import com.advertisementsystem.Mapper.AdvertisementMapper;
import com.advertisementsystem.Mapper.StatisticsMapper;
import com.advertisementsystem.entity.Advertisement;
import com.advertisementsystem.entity.Schedule;
import com.advertisementsystem.entity.Statistics;

import com.advertisementsystem.vo.AdSchedule;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 设备任务调度类
 * 定期查询排期信息并更新统计数据
 */
@Component
@Slf4j
public class deviceTask {

    @Autowired
    private AdScheduleMapper adScheduleMapper;

    @Autowired
    private StatisticsMapper statisticsMapper;

    @Autowired
    private AdvertisementMapper advertisementMapper;

    /**
     * 每半小时执行一次查询排期并更新统计数据
     * cron表达式：秒 分 时 日 月 周
     * 0 0/30 * * * ? 表示每半小时（每小时的0分和30分）执行一次
     */
    @Scheduled(cron = "0 0/30 * * * ?")
    // @Scheduled(fixedRate = 10 * 1000)
    @Transactional
    public void checkAndUpdateSchedules() {
        log.info("开始执行广告排期定时检查任务 - {}", LocalDateTime.now());

        try {
            // 查询当前正在运行的广告排期
            LambdaQueryWrapper<Schedule> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Schedule::getStatus, "RUNNING");

            List<Schedule> runningSchedules = adScheduleMapper.selectList(wrapper);
            log.info("找到 {} 个正在运行的广告排期", runningSchedules.size());

            LocalDateTime now = LocalDateTime.now();
            LocalDate today = LocalDate.now();

            // 处理每个运行中的排期
            for (Schedule schedule : runningSchedules) {
                try {
                    // 检查是否已到结束时间
                    if (now.isAfter(schedule.getEndTime())) {
                        // 更新状态为已完成
                        schedule.setStatus("COMPLETED");
                        schedule.setUpdatedTime(now);
                        adScheduleMapper.updateById(schedule);
                        log.info("排期 ID {} 已完成", schedule.getId());
                        continue;
                    }

                    // 更新播放次数和观看次数
                    updateStatistics(schedule.getAdvertisementId(), schedule.getDeviceId(), today);

                } catch (Exception e) {
                    log.error("处理排期 ID {} 时发生错误", schedule.getId(), e);
                }
            }

            // 检查待执行的排期，如果到了开始时间，就更新为运行中
            LambdaQueryWrapper<Schedule> pendingWrapper = new LambdaQueryWrapper<>();
            pendingWrapper.eq(Schedule::getStatus, "PENDING")
                    .le(Schedule::getStartTime, now); // 开始时间小于等于当前时间

            List<Schedule> pendingSchedules = adScheduleMapper.selectList(pendingWrapper);
            log.info("找到 {} 个需要开始的待执行排期", pendingSchedules.size());

            for (Schedule schedule : pendingSchedules) {
                try {
                    // 如果已经超过结束时间，则直接标记为已完成
                    if (now.isAfter(schedule.getEndTime())) {
                        schedule.setStatus("COMPLETED");
                    } else {
                        // 否则更新为运行中
                        schedule.setStatus("RUNNING");
                    }

                    schedule.setUpdatedTime(now);
                    adScheduleMapper.updateById(schedule);
                    log.info("排期 ID {} 状态已更新为 {}", schedule.getId(), schedule.getStatus());

                    // 为新开始的排期初始化统计记录
                    if ("RUNNING".equals(schedule.getStatus())) {
                        initializeStatistics(schedule.getAdvertisementId(), schedule.getDeviceId(), today);
                    }

                } catch (Exception e) {
                    log.error("更新排期 ID {} 状态时发生错误", schedule.getId(), e);
                }
            }

            log.info("广告排期定时检查任务执行完成");

        } catch (Exception e) {
            log.error("执行广告排期定时检查任务时发生错误", e);
        }
    }

    /**
     * 更新广告统计信息
     * 每次定时任务执行时，为每个运行中的排期增加一次播放计数
     */
    private void updateStatistics(Long adId, Long deviceId, LocalDate date) {
        try {
            // 查找当天的统计记录
            LambdaQueryWrapper<Statistics> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Statistics::getAdId, adId)
                    .eq(Statistics::getDeviceId, deviceId)
                    .eq(Statistics::getDate, date);

            Statistics statistics = statisticsMapper.selectOne(wrapper);

            if (statistics == null) {
                // 如果不存在则创建新记录
                statistics = new Statistics();
                statistics.setAdId(adId);
                statistics.setDeviceId(deviceId);
                statistics.setDate(date);
                statistics.setPlayCount(1); // 初始化播放次数为1
                statistics.setViewCount(0); // 假设暂无观看
                statistics.setCreatedTime(LocalDateTime.now());
                statistics.setUpdatedTime(LocalDateTime.now());

                statisticsMapper.insert(statistics);
                log.info("为广告 ID {} 设备 ID {} 创建新的统计记录", adId, deviceId);
            } else {
                // 如果存在则增加播放次数
                statistics.setPlayCount(statistics.getPlayCount() + 1);
                statistics.setUpdatedTime(LocalDateTime.now());
                simulateViews(adId, deviceId,date);
                statisticsMapper.updateById(statistics);
                log.info("更新广告 ID {} 设备 ID {} 的统计记录，播放次数 +1", adId, deviceId);
            }
        } catch (Exception e) {
            log.error("更新统计信息时发生错误，广告 ID: {}, 设备 ID: {}", adId, deviceId, e);
        }
    }

    /**
     * 初始化统计记录
     * 当排期首次开始运行时调用
     */
    private void initializeStatistics(Long adId, Long deviceId, LocalDate date) {
        try {
            // 查找当天的统计记录
            LambdaQueryWrapper<Statistics> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Statistics::getAdId, adId)
                    .eq(Statistics::getDeviceId, deviceId)
                    .eq(Statistics::getDate, date);

            Statistics statistics = statisticsMapper.selectOne(wrapper);

            // 如果不存在则创建新记录
            if (statistics == null) {
                statistics = new Statistics();
                statistics.setAdId(adId);
                statistics.setDeviceId(deviceId);
                statistics.setDate(date);
                statistics.setPlayCount(0);
                statistics.setViewCount(0);
                statistics.setCreatedTime(LocalDateTime.now());
                statistics.setUpdatedTime(LocalDateTime.now());

                statisticsMapper.insert(statistics);
                log.info("为新启动的排期初始化统计记录，广告 ID: {}, 设备 ID: {}", adId, deviceId);
            }
        } catch (Exception e) {
            log.error("初始化统计记录时发生错误，广告 ID: {}, 设备 ID: {}", adId, deviceId, e);
        }
    }

    /**
     * 随机增加观看次数（模拟观众观看）
     * 在实际应用中，这部分应该由设备的传感器或交互系统触发
     */
    private void simulateViews(Long adId, Long deviceId, LocalDate date) {
        try {
            // 查找当天的统计记录
            LambdaQueryWrapper<Statistics> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Statistics::getAdId, adId)
                    .eq(Statistics::getDeviceId, deviceId)
                    .eq(Statistics::getDate, date);

            Statistics statistics = statisticsMapper.selectOne(wrapper);

            if (statistics != null) {
                // 随机决定是否增加观看次数 (假设30%的播放会被观看)
                if (Math.random() < 0.3) {
                    statistics.setViewCount(statistics.getViewCount() + 1);
                    statistics.setUpdatedTime(LocalDateTime.now());

                    statisticsMapper.updateById(statistics);
                    LambdaQueryWrapper<Schedule>  wrapper1 = new LambdaQueryWrapper<>();
                    wrapper1.eq(Schedule::getAdvertisementId,adId)
                            .eq(Schedule::getDeviceId,deviceId)
                            .eq(Schedule::getStatus,"RUNNING");
                    Schedule schedule = adScheduleMapper.selectOne(wrapper1);
                    schedule.setImpressions(schedule.getImpressions()+1);
                    schedule.setClicks(schedule.getClicks()+1);
                    adScheduleMapper.updateById(schedule);
                    log.info("模拟广告 ID {} 设备 ID {} 的观看次数 +1", adId, deviceId);
                }
            }
        } catch (Exception e) {
            log.error("模拟观看次数更新时发生错误，广告 ID: {}, 设备 ID: {}", adId, deviceId, e);
        }
    }
}